#!/bin/bash

#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#

#
# Copyright 2022 Joyent, Inc.
#

#
# This script will repair a Triton installation that cannot self-update.
# Necessary images (ignoring certificate errors) will be downloaded and
# manually installed. After this is complete, self-update should work
# normally again.
#
# If a failure occurs, completed downloads will be checked against the sha1
# sum in the image manifest. If the checksum is correct, the file will be
# retained and used. If the checksum is not correct, another attempt to
# download it will be made. This also means that if you have network
# connectivity issues you can download these on an alternate system and scp
# them to the headnode.
#
# Note: If this script is necessary, it is likely that the necessary images
# require a newer min_platform. In this case, the platform image on the
# headnode will be updated and a reboot required before the rest of the script
# can proceed.
#
# Also note: This is not a general purpose script. All of the images are
# hard coded to a specific version and will only work on Triton dating
# *before* 2022. This script is *not* highly intelligent. That's what sdcadm
# is for. This one is only if your sdcadm is broken.
# If you attempt to use this on a Triton with components from 2022 or later
# you may cause damage to your installation. You have been warned.
#


# Prep ################################################################

# from: https://gist.github.com/bahamat/0a95e2cf70aca9944bdbc2a9763f2920 
# Fork-lift a Triton install that is unable to self-update

set -o pipefail
set -o errexit
shopt -s expand_aliases

# If the updates server URL ever changes, it can be overridden with this.
# export UPDATES_IMGADM_URL=https://updates.joyent.com

alias updates-imgadm='updates-imgadm --insecure'

if [[ -n "$TRACE" ]]; then
    export PS4='[\D{%FT%TZ}] ${BASH_SOURCE}:${LINENO}: ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
    set -o xtrace
fi

# These are the image UUIDs that we'll be updating to.
sdcadm_stamp=release-20220310-20220310T015322Z-g07059cc
sdcadm=448627ba-a015-11ec-9d1e-33fe0eee8f5c
imgapi=776a1f95-a779-40bf-8eb2-ccb711614e5e
origin=a9368831-958e-432d-a031-f8ce6768d190
minimal=c2c31b00-1d60-11e9-9a77-ff9f06554b0f

if uname -v | grep -q joyent_ ; then
    if ! bootparams | grep -q headnode; then
        printf 'Fatal: This must be run from a Triton headnode.\n'
        exit 1
    fi
fi

cd /var/tmp/ || {
    printf 'Fatal: Could not chdir to /var/tmp\n'
    exit 1
}

# Platform ############################################################

if uname -v | grep -q joyent_ ; then
    cur_platform=$(sdc-cnapi /servers?hostname=headnode | json -Ha current_platform | cut -d T -f 1)
    # This is the minimum platform needed for images below.
    min_platform=20181206

    if (( cur_platform < min_platform )); then
        pi=20220310T212952Z
        platform=d48b86f6-c37a-45e5-a48e-cff19950ccc6

        printf 'Newer platform image is needed.\n'
        printf 'Downloading platform 20181206T011455Z...\n'
        updates-imgadm get-file -C release "$platform"

        mv "${platform}-file.gz" "platform-${pi}.tgz"

        sdcadm platform install "./platform-${pi}.tgz"
        sdcadm platform assign --latest --all
        printf '\n\n=========================================\n'
        printf 'A new platform has been installed. You need to reboot\n'
        printf 'and run this script again to continue.\n'
        exit
    else
        printf 'Current platform %s is sufficient\n' "$(uname -v | tr -d 'joyent_')"
    fi
fi

# Images ##############################################################

function check_sum() {
    if ! [[ -f ${1}-file ]] && ! [[ -f ${1}-file.gz ]]; then
        return 1
    fi
    m_sum=$(json -f "${1}.json" files.0.sha1)
    f_sum=$(openssl sha1 "${1}"-file* | cut -d ' ' -f 2)
    if [[ "$m_sum" == "$f_sum" ]]; then
        printf 'Cached file is OK\n'
        return 0
    else
        return 1
    fi
}

##### sdcadm
printf 'Downloading sdcadm...\n'
updates-imgadm get -C release "$sdcadm" > "${sdcadm}.json"
check_sum "$sdcadm" || updates-imgadm get-file -C release -O "$sdcadm"

##### minimal
printf 'Downloading minimal image...\n'
updates-imgadm get -C release "$minimal" > "${minimal}.json"
check_sum "$minimal" || updates-imgadm get-file -C release -O "$minimal"

##### origin
printf 'Downloading origin image...\n'
updates-imgadm get -C release "$origin" > "${origin}.json"
check_sum "$origin" || updates-imgadm get-file -C release -O "$origin"

##### imgapi
printf 'Downloading imgapi image...\n'
updates-imgadm get -C release "$imgapi" > "${imgapi}.json"
check_sum "$imgapi" || updates-imgadm get-file -C release -O "$imgapi"

sdc-imgadm get "$minimal" > /dev/null || sdc-imgadm import -f "${minimal}-file.gz" -m "${minimal}.json"
sdc-imgadm get "$origin" > /dev/null || sdc-imgadm import -f "${origin}-file.gz" -m "${origin}.json"
sdc-imgadm get "$imgapi" > /dev/null || sdc-imgadm import -f "${imgapi}-file.gz" -m "${imgapi}.json"

# Install #############################################################

if ! grep -q "$sdcadm_stamp" /opt/smartdc/sdcadm/etc/buildstamp ; then
    chmod +x "${sdcadm}-file"
    ./"${sdcadm}-file"
else
    printf 'sdcadm is already up to date\n'
fi

cur_imgapi=$(sdcadm insts imgapi -j | json -a image)
if [[ "$cur_imgapi" != "$imgapi" ]]; then
    imgadm import "$minimal"
    imgadm import "$origin"
    imgadm import "$imgapi"

    sdcadm update -y "imgapi@$imgapi"
else
    printf 'imgapi is alread up to date\n'
fi

printf 'Now you should be able to update everything else normally\n'